package org.cgc.log;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.swing.JOptionPane;

import org.cgc.obj.DNA;
import org.cgc.obj.Graph;
import org.cgc.obj.GraphColoringInfo;

public class GraphLogic {
	
	public static int maxIterations = 5000;
	
	private static List<Integer> forbiddenDistances;
	
	public static void colorGraph(Graph g, GraphColoringInfo gci) {
		
		Date start = new Date();
		
		//initialize population
		int pNumber = 500;
		DNA[] dna = new DNA[pNumber];
		int[] note = new int[pNumber];
		
		for(int i = 0; i < dna.length; i++) {
			dna[i] = new DNA(g.getVertNumber(), g.getVertNumber());
		}
		
		//proces ewolucji
		int count = 0;
		int globalCount = 0;
		double avg = 0;
		double oldAvg = 0;
		while(true) {
			DNALogic.evaluation(g, dna, note);
			
			//warunek konca
			oldAvg = avg;
			for(int i = 0; i < note.length; i++) {
				avg += note[i];
			}
			avg /= note.length;
			//System.out.println(avg);
			
			if(Math.abs(avg - oldAvg) < 0.1 * g.getVertNumber()) {
				count++;
				if(count > 1000) break;
			} else {
				count = 0;
			}
			
			globalCount++;
			if(globalCount > maxIterations) break;
			
			dna = DNALogic.selection(dna, note);
			DNALogic.crossover(g, dna);
			DNALogic.mutation(g, dna);
		}
		
		Date end = new Date();
		
		//najlepszy osobnik
		DNA best = dna[getTheBestDNA(note)];
		GraphLogic.initGraph(g, best);
		
		gci.setColorsUsed(DNALogic.maxColor(best)+1);
		gci.setNote(DNALogic.evaluateDNA(g, best));
		gci.setAvgNote(avg);
		gci.setTime((int)(end.getTime() - start.getTime()));
		gci.setEpochs(globalCount);
	}
	
	public static void initGraph(Graph g, DNA dna) {
		for(int i = 0; i < dna.getSize(); i++) {
			g.setColor(i, dna.getGene(i));
		}
	}
	
	public static int getTheBestDNA(int[] note) {
		int imin = 0;
		for(int i = 1; i < note.length; i++) {
			if(note[imin] > note[i]) imin = i;
		}
		return imin;
	}
	
	public static int maxColor(Graph g) {
		int max = 0;
		for(int i = 0; i < g.getVertNumber(); i++) {
			if(g.getColor(i) > max) max = g.getColor(i);
		}
		return max;
	}
	
	public static boolean forbiddenColors(Graph g, int clr1, int clr2) {
		int dist = Math.abs(clr1 - clr2);
		Iterator<Integer> it = forbiddenDistances.iterator();
		while(it.hasNext()) {
			if(dist == it.next().intValue()) {
				return true;
			}
		}
		return false;
	}
	
	public static boolean initForbiddenDistances(String string) {
		if(string.isEmpty()) return false;
		
		List<Integer> temp = new ArrayList<Integer>();
		string = string.replaceAll(" ", "");
		int indx = string.indexOf(",");
		int dist;
		while(indx >= 0) {
			try {
			dist = Integer.parseInt(string.substring(0, indx));
			} catch(NumberFormatException ex) {
				return false;
			}
			temp.add(dist);
			if(indx+1 >= string.length()) break;
			string = string.substring(indx+1);
			indx = string.indexOf(",");
		}
		
		//last one
		if(!string.isEmpty()) {
			try {
				dist = Integer.parseInt(string);
			} catch(NumberFormatException ex) {
				return false;
			}
			temp.add(dist);
		}
		
		forbiddenDistances = temp;
		return true;
	}
	
	public static String getForbiddenDistances() {
		String dist = "";
		Iterator<Integer> it = forbiddenDistances.iterator();
		if(it.hasNext()) {
			dist += it.next().intValue();
		}
		while(it.hasNext()) {
			dist += "," + it.next().intValue();
		}
		return dist;
	}
	
	public static void initGraph(Graph graph, File file) {
		BufferedReader stream = null;
		String line = null;

		Graph temp = null;
		try {
			stream = new BufferedReader(new FileReader(file.getAbsoluteFile()));
			
			if (!stream.ready()) throw new IOException();
			
			int size = 0;
			if((line = stream.readLine()) != null) {
				size = Integer.parseInt(line);
			}
			
			boolean[][] edges = new boolean[size][];
			for(int i = 0; i < size; i++) {
				edges[i] = new boolean[size];
				line = stream.readLine();
				for(int j = 0; j < size-1; j++) {
					if(Integer.parseInt(line.substring(0, 1)) != 0) {
						edges[i][j] = true;
					}
					line = line.substring(2);
				}
				if(Integer.parseInt(line.substring(0, 1)) != 0) {
					edges[i][size-1] = true;
				}
			}
			temp = new Graph(edges);
		}
		catch(FileNotFoundException ex) {
			JOptionPane.showMessageDialog(null, "Specified file does not exist.");
			return;
		}
		catch(Exception ex) {
			JOptionPane.showMessageDialog(null, "Cannot read this file. Make shure it is in right format.");
			return;
		}
		finally {
			try {
				if(stream != null)
					stream.close();
			}
			catch (IOException ex) {
				JOptionPane.showMessageDialog(null, "Internal loading error 01.");
				return;
			}
		}
		if(temp != null) {
			temp.copyTo(graph);
		}
	}
	
	public static void saveGraph(Graph graph, File file) {
		BufferedWriter stream = null;
		try {
			stream = new BufferedWriter(new FileWriter(file.getAbsoluteFile()));
			
			String line = "" + graph.getVertNumber();
			stream.write(line);
            stream.newLine();
			
			for(int i = 0; i < graph.getVertNumber(); i++) {
				if(graph.isEdge(i, 0)) {
					line = "1";
				} else {
					line = "0";
				}
				for(int j = 1; j < graph.getVertNumber(); j++) {
					if(graph.isEdge(i, j)) {
						line += " 1";
					} else {
						line += " 0";
					}
				}
				stream.write(line);
				stream.newLine();
			}
		}
		catch(FileNotFoundException ex) {
			JOptionPane.showMessageDialog(null, "Specified file does not exist.");
			return;
		}
		catch(Exception ex) {
			JOptionPane.showMessageDialog(null, "Internal saving error 01.");
			return;
		}
		finally {
			try {
				if(stream != null)
					stream.close();
			}
			catch (IOException ex) {
				JOptionPane.showMessageDialog(null, "Internal saving error 02.");
			}
		}
	}
	
	public static void saveColoredGraph(Graph graph, File file) {
		//TODO
	}
}
